home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Resources / Online / Term / Extras / Source / term-source.lha / Job.c < prev    next >
C/C++ Source or Header  |  1996-10-20  |  10KB  |  548 lines

  1. /*
  2. **    Job.c
  3. **
  4. **    Primitive event job scheduler
  5. **
  6. **    Copyright © 1990-1996 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16. /****************************************************************************/
  17.  
  18.     /* NullQueue(JobQueue *Queue):
  19.      *
  20.      *    Does nothing; called if waiting on a queue that doesn't have
  21.      *    any wait mask set. The SIGF_SINGLE bit is added in order
  22.      *    to trigger JOBTYPE_Once jobs.
  23.      */
  24.  
  25. STATIC ULONG
  26. NullQueue(JobQueue *UnusedQueue)
  27. {
  28.     DB(kprintf("%s: %s\n",RexxPortName,__FUNC__));
  29.  
  30.     return(SIGF_SINGLE);
  31. }
  32.  
  33.     /* WaitQueue(JobQueue *Queue):
  34.      *
  35.      *    Wait for any event to take place.
  36.      */
  37.  
  38. STATIC ULONG
  39. WaitQueue(JobQueue *Queue)
  40. {
  41.     DB(kprintf("%s: %s %08lx\n",RexxPortName,__FUNC__,Queue->ReadyMask));
  42.  
  43.     return(Wait(Queue->ReadyMask));
  44. }
  45.  
  46.     /* CheckQueue(JobQueue *Queue):
  47.      *
  48.      *    Don't wait for any event to take place, just check if any
  49.      *    signals are waiting. The SIGF_SINGLE bit is added in order
  50.      *    to trigger JOBTYPE_Once jobs.
  51.      */
  52.  
  53. STATIC ULONG
  54. CheckQueue(JobQueue *Queue)
  55. {
  56.     DB(kprintf("%s: %s\n",RexxPortName,__FUNC__));
  57.  
  58.     return(SIGF_SINGLE | (SetSignal(0,Queue->ReadyMask) & Queue->ReadyMask));
  59. }
  60.  
  61. /****************************************************************************/
  62.  
  63.     /* CallJobOnce(JobNode *Job):
  64.      *
  65.      *    Calls a job once, then removes it from the queue.
  66.      */
  67.  
  68. STATIC BOOL
  69. CallJobOnce(JobNode *Job)
  70. {
  71.     DB(kprintf("%s: %s\n",RexxPortName,__FUNC__));
  72.  
  73.     (*Job->SubFunction)(Job);
  74.  
  75.     SuspendJob(Job->HomeQueue,Job);
  76.  
  77.     return(FALSE);
  78. }
  79.  
  80.     /* DisposeJobOnce(JobNode *Job):
  81.      *
  82.      *    Calls a job once, then removes it from the queue and deletes it.
  83.      */
  84.  
  85. STATIC BOOL
  86. DisposeJobOnce(JobNode *Job)
  87. {
  88.     DB(kprintf("%s: %s\n",RexxPortName,__FUNC__));
  89.  
  90.     (*Job->SubFunction)(Job);
  91.  
  92.     RemoveJob(Job->HomeQueue,Job);
  93.  
  94.     DeleteJob(Job);
  95.  
  96.     return(FALSE);
  97. }
  98.  
  99. /****************************************************************************/
  100.  
  101.     /* RebuildReadyMask(JobQueue *Queue):
  102.      *
  103.      *    Rebuilds the wait mask for the queue and installs the
  104.      *    right routine to wait for something to happen.
  105.      */
  106.  
  107. STATIC VOID
  108. RebuildReadyMask(JobQueue *Queue)
  109. {
  110.     JobNode *Node;
  111.     ULONG Mask;
  112.  
  113.         /* Collect the mask bits. */
  114.  
  115.     for(Node = (JobNode *)Queue->ReadyList.mlh_Head, Mask = NULL ; Node->Node.ln_Succ ; Node = (JobNode *)Node->Node.ln_Succ)
  116.     {
  117.         if(Node->Type == JOBTYPE_Wait)
  118.             Mask |= Node->Mask;
  119.     }
  120.  
  121.     Queue->ReadyMask = Mask;
  122.  
  123.         /* If we have JOBTYPE_Once jobs, use the routine
  124.          * that just checks for the signals.
  125.          */
  126.  
  127.     if(Queue->OnceCounter > 0)
  128.         Queue->QueueWait = CheckQueue;
  129.     else
  130.     {
  131.             /* If we don't have any signals to wait for,
  132.              * use the dummy routine, otherwise wait
  133.              * for something to happen.
  134.              */
  135.  
  136.         if(Mask == NULL)
  137.             Queue->QueueWait = NullQueue;
  138.         else
  139.             Queue->QueueWait = WaitQueue;
  140.     }
  141. }
  142.  
  143.     /* GetNextJob(JobNode *Job):
  144.      *
  145.      *    Returns the next job to follow the given one.
  146.      */
  147.  
  148. STATIC JobNode *
  149. GetNextJob(JobNode *Job)
  150. {
  151.     if(Job->Node.ln_Succ->ln_Succ)
  152.         return((JobNode *)Job->Node.ln_Succ);
  153.     else
  154.         return(NULL);
  155. }
  156.  
  157.     /* GetFirstJob(JobQueue *Queue):
  158.      *
  159.      *    Returns the first job of the active list.
  160.      */
  161.  
  162. STATIC JobNode *
  163. GetFirstJob(JobQueue *Queue)
  164. {
  165.     if(IsListEmpty((struct List *)&Queue->ReadyList))
  166.         return(NULL);
  167.     else
  168.         return((JobNode *)Queue->ReadyList.mlh_Head);
  169. }
  170.  
  171. /****************************************************************************/
  172.  
  173.     /* DeleteJobQueue(JobQueue *Queue):
  174.      *
  175.      *    Deletes a job queue, releases the allocated memory.
  176.      */
  177.  
  178. VOID
  179. DeleteJobQueue(JobQueue *Queue)
  180. {
  181.     FreeVecPooled(Queue);
  182. }
  183.  
  184.     /* CreateJobQueue():
  185.      *
  186.      *    Creates a job queue and initializes its defaults.
  187.      */
  188.  
  189. JobQueue *
  190. CreateJobQueue()
  191. {
  192.     JobQueue *Queue;
  193.  
  194.     if(Queue = (JobQueue *)AllocVecPooled(sizeof(JobQueue),MEMF_ANY|MEMF_CLEAR))
  195.     {
  196.         NewList((struct List *)&Queue->ReadyList);
  197.  
  198.         InitSemaphore(&Queue->AccessLock);
  199.  
  200.         RebuildReadyMask(Queue);
  201.     }
  202.  
  203.     return(Queue);
  204. }
  205.  
  206.     /* DeleteJob(JobNode *Node):
  207.      *
  208.      *    Deletes a job node, releases the allocated memory.
  209.      */
  210.  
  211. VOID
  212. DeleteJob(JobNode *Node)
  213. {
  214.     FreeVecPooled(Node);
  215. }
  216.  
  217.     /* CreateJob(STRPTR Name,WORD Type,JOBFUNCTION Function,ULONG Mask):
  218.      *
  219.      *    Creates a new job node with name, type, invocation function
  220.      *    and signal mask.
  221.      */
  222.  
  223. JobNode *
  224. CreateJob(STRPTR Name,WORD Type,JOBFUNCTION Function,ULONG Mask)
  225. {
  226.     JobNode *Job;
  227.     LONG Extra;
  228.  
  229.         /* Add extra space if name is given. */
  230.  
  231.     if(Name)
  232.         Extra = strlen(Name) + 1;
  233.     else
  234.         Extra = 0;
  235.  
  236.     if(Job = (JobNode *)AllocVecPooled(sizeof(JobNode) + Extra,MEMF_ANY|MEMF_CLEAR))
  237.     {
  238.             /* Fill in the name. */
  239.  
  240.         if(Name)
  241.             strcpy(Job->Node.ln_Name = (char *)(Job + 1),Name);
  242.         else
  243.             Job->Node.ln_Name = "Untitled";
  244.  
  245.             /* Remember the type. */
  246.  
  247.         Job->Type = Type;
  248.  
  249.             /* JOBTYPE_Once jobs are special. They will invoke the
  250.              * routine to call and immediately remove the job from
  251.              * the active list.
  252.              */
  253.  
  254.         if(Job->Type != JOBTYPE_Wait)
  255.         {
  256.             Job->SubFunction    = Function;
  257.             Job->Mask            = (ULONG)~0;
  258.  
  259.             switch(Job->Type)
  260.             {
  261.                 case JOBTYPE_Once:
  262.  
  263.                     Job->Function = CallJobOnce;
  264.                     break;
  265.  
  266.                 case JOBTYPE_Always:
  267.  
  268.                     Job->Function = Function;
  269.                     break;
  270.  
  271.                 case JOBTYPE_Disposable:
  272.  
  273.                     Job->SubFunction = DisposeJobOnce;
  274.                     break;
  275.             }
  276.         }
  277.         else
  278.         {
  279.             Job->Function    = Function;
  280.             Job->Mask        = Mask;
  281.         }
  282.     }
  283.  
  284.     return(Job);
  285. }
  286.  
  287.     /* RemoveJob(JobQueue *Queue,JobNode *Job):
  288.      *
  289.      *    Remove a job from the active list.
  290.      */
  291.  
  292. VOID
  293. RemoveJob(JobQueue *Queue,JobNode *Job)
  294. {
  295.     DB(kprintf("%s: %s %s\n",RexxPortName,__FUNC__,Job->Node.ln_Name));
  296.  
  297.     if(Job->Active)
  298.     {
  299.         ObtainSemaphore(&Queue->AccessLock);
  300.  
  301.         Remove((struct Node *)Job);
  302.  
  303.         if(Job->Type != JOBTYPE_Wait)
  304.             Queue->OnceCounter--;
  305.  
  306.         RebuildReadyMask(Queue);
  307.  
  308.         if(Job == Queue->NextJob)
  309.             Queue->NextJob = GetNextJob(Job);
  310.  
  311.         Job->Active = FALSE;
  312.  
  313.         ReleaseSemaphore(&Queue->AccessLock);
  314.     }
  315. }
  316.  
  317.     /* AddJob(JobQueue *Queue,JobNode *Job):
  318.      *
  319.      *    Add a list to the active job list.
  320.      */
  321.  
  322. VOID
  323. AddJob(JobQueue *Queue,JobNode *Job)
  324. {
  325.     ObtainSemaphore(&Queue->AccessLock);
  326.  
  327.     if(Queue->NextJob == NULL)
  328.         Queue->NextJob = Job;
  329.  
  330.     AddTail((struct List *)&Queue->ReadyList,(struct Node *)Job);
  331.  
  332.     Job->Active = TRUE;
  333.     Job->HomeQueue = Queue;
  334.  
  335.     if(Job->Type != JOBTYPE_Wait)
  336.         Queue->OnceCounter++;
  337.  
  338.     RebuildReadyMask(Queue);
  339.  
  340.     ReleaseSemaphore(&Queue->AccessLock);
  341. }
  342.  
  343.     /* SuspendJob(JobQueue *Queue,JobNode *Job):
  344.      *
  345.      *    Suspend an active job.
  346.      */
  347.  
  348. VOID
  349. SuspendJob(JobQueue *Queue,JobNode *Job)
  350. {
  351.     DB(kprintf("%s: %s %s\n",RexxPortName,__FUNC__,Job->Node.ln_Name));
  352.  
  353.     ObtainSemaphore(&Queue->AccessLock);
  354.  
  355.     if(Job->Active)
  356.         RemoveJob(Queue,Job);
  357.  
  358.     ReleaseSemaphore(&Queue->AccessLock);
  359. }
  360.  
  361.     /* ActivateJob(JobQueue *Queue,JobNode *Job):
  362.      *
  363.      *    Reactivate a suspended job.
  364.      */
  365.  
  366. VOID
  367. ActivateJob(JobQueue *Queue,JobNode *Job)
  368. {
  369.     DB(kprintf("%s: %s %s\n",RexxPortName,__FUNC__,Job->Node.ln_Name));
  370.  
  371.     ObtainSemaphore(&Queue->AccessLock);
  372.  
  373.     if(!Job->Active)
  374.         AddJob(Queue,Job);
  375.  
  376.     ReleaseSemaphore(&Queue->AccessLock);
  377. }
  378.  
  379.     /* UpdateJobMask(JobQueue *Queue,JobNode *Job,ULONG Mask):
  380.      *
  381.      *    Update a job wait mask.
  382.      */
  383.  
  384. VOID
  385. UpdateJobMask(JobQueue *Queue,JobNode *Job,ULONG Mask)
  386. {
  387.     DB(kprintf("%s: %s %s\n",RexxPortName,__FUNC__,Job->Node.ln_Name));
  388.  
  389.     if(Job->Type == JOBTYPE_Wait)
  390.     {
  391.         ObtainSemaphore(&Queue->AccessLock);
  392.  
  393.         Job->Mask = Mask;
  394.  
  395.         RebuildReadyMask(Queue);
  396.  
  397.         ReleaseSemaphore(&Queue->AccessLock);
  398.     }
  399. }
  400.  
  401.     /* UpdateJob(JobQueue *Queue,JobNode *Job,ULONG Mask):
  402.      *
  403.      *    Activate or susped a job based upon the signal mask.
  404.      *    If the mask is not NULL, the job mask will be updated,
  405.      *    otherwise it will be suspended.
  406.      */
  407.  
  408. VOID
  409. UpdateJob(JobQueue *Queue,JobNode *Job,ULONG Mask)
  410. {
  411.     if(Queue && Job)
  412.     {
  413.         DB(kprintf("%s: %s %s\n",RexxPortName,__FUNC__,Job->Node.ln_Name));
  414.  
  415.         if(Job->Type == JOBTYPE_Wait)
  416.         {
  417.             if(Mask == NULL)
  418.                 SuspendJob(Queue,Job);
  419.             else
  420.             {
  421.                 ObtainSemaphore(&Queue->AccessLock);
  422.  
  423.                 ActivateJob(Queue,Job);
  424.  
  425.                 UpdateJobMask(Queue,Job,Mask);
  426.  
  427.                 ReleaseSemaphore(&Queue->AccessLock);
  428.             }
  429.         }
  430.     }
  431. }
  432.  
  433.     /* GetJobMask(JobNode *Job):
  434.      *
  435.      *    Get the job wait signal mask, if any.
  436.      */
  437.  
  438. ULONG
  439. GetJobMask(JobNode *Job)
  440. {
  441.     ULONG Mask;
  442.  
  443.     DB(kprintf("%s: %s %s\n",RexxPortName,__FUNC__,Job->Node.ln_Name));
  444.  
  445.     Mask = NULL;
  446.  
  447.     if(Job)
  448.     {
  449.         if(Job->Active && Job->Type == JOBTYPE_Wait)
  450.             Mask = Job->Mask;
  451.     }
  452.  
  453.     return(Mask);
  454. }
  455.  
  456.     /* RunJob(JobNode *Job):
  457.      *
  458.      *    Run a single job unless it has been suspended.
  459.      */
  460.  
  461. BOOL
  462. RunJob(JobNode *Job)
  463. {
  464.     DB(kprintf("%s: %s %s\n",RexxPortName,__FUNC__,Job->Node.ln_Name));
  465.  
  466.         /* Check if the job is an active one. */
  467.  
  468.     if(Job->Active)
  469.         return((*Job->Function)(Job));
  470.     else
  471.         return(FALSE);
  472. }
  473.  
  474.     /* ProcessJobQueue(JobQueue *Queue):
  475.      *
  476.      *    This is where the work takes place.
  477.      */
  478.  
  479. VOID
  480. ProcessJobQueue(JobQueue *Queue)
  481. {
  482.     ULONG Signals;
  483.     JobNode *Job;
  484.     BOOL Running;
  485.  
  486.     DB(kprintf("%s: waiting (mask %08lx)...\n",RexxPortName,Queue->ReadyMask));
  487.  
  488.         /* Wait for something to happen. */
  489.  
  490.     Signals = (*Queue->QueueWait)(Queue);
  491.  
  492.     DB(kprintf("%s: got %08lx\n",RexxPortName,Signals));
  493.  
  494.         /* Prepare to walk down the list. */
  495.  
  496.     ObtainSemaphore(&Queue->AccessLock);
  497.  
  498.     while(TRUE)
  499.     {
  500.             /* Nothing has happened, yet. */
  501.  
  502.         Running = FALSE;
  503.  
  504.             /* Walk down the list... */
  505.  
  506.         while(Job = Queue->NextJob)
  507.         {
  508.             Queue->NextJob = GetNextJob(Job);
  509.  
  510.             DB(kprintf("%s: checking |%s| mask %08lx & job = %08lx\n",RexxPortName,Job->Node.ln_Name,Job->Mask,Signals & Job->Mask));
  511.  
  512.                 /* Work to be done by this job? */
  513.  
  514.             if(Signals & Job->Mask)
  515.             {
  516.                     /* Drop the access lock. */
  517.  
  518.                 ReleaseSemaphore(&Queue->AccessLock);
  519.  
  520.                     /* Do the job. */
  521.  
  522.                 DB(kprintf("%s: do job |%s|\n",RexxPortName,Job->Node.ln_Name));
  523.                 Running |= (*Job->Function)(Job);
  524.  
  525.                     /* And pick up the lock again. */
  526.  
  527.                 ObtainSemaphore(&Queue->AccessLock);
  528.             }
  529.         }
  530.  
  531.             /* Stop if the list is empty now, otherwise
  532.              * restart at the top of the list.
  533.              */
  534.  
  535.         if(!(Queue->NextJob = GetFirstJob(Queue)))
  536.             break;
  537.  
  538.             /* If there isn't more work to be done, leave the loop. */
  539.  
  540.         if(!Running)
  541.             break;
  542.     }
  543.  
  544.         /* Drop the access lock. */
  545.  
  546.     ReleaseSemaphore(&Queue->AccessLock);
  547. }
  548.